﻿using System;
using System.Linq;
using Microsoft.Xna.Framework;
using NuclearWinter.GameFlow;
using StoCombatLogHUD.Parsing;
using StoCombatLogHUD.Statistics.StatisticsEntries;
using StoCombatLogHUD.Toolkit;
using StoCombatLogHUD.Toolkit.ExtensionMethods;
using NuclearUI = NuclearWinter.UI;

namespace StoCombatLogHUD.GameStates
{
	/// <summary>
	/// 
	/// </summary>
	public class DetailDisplayState : GameStateFadeTransition<Main>
	{
		/// <summary>
		/// Gets or sets the detailed statistics.
		/// </summary>
		/// <value>
		/// The detailed statistics.
		/// </value>
		private NuclearUI.ListView DetailedStatistics { get; set; }

		/// <summary>
		/// Gets or sets the display panel.
		/// </summary>
		/// <value>
		/// The display panel.
		/// </value>
		private NuclearUI.Panel DisplayPanel { get; set; }

		/// <summary>
		/// Gets or sets the name of the player.
		/// </summary>
		/// <value>
		/// The name of the player.
		/// </value>
		private string PlayerName { get; set; }

		/// <summary>
		/// Initializes a new instance of the <see cref="DetailDisplayState" /> class.
		/// </summary>
		/// <param name="game">The game.</param>
		/// <param name="playerName">The target player name.</param>
		public DetailDisplayState(Main game, string playerName)
			: base(game)
		{
			PlayerName = playerName;

			DetailedStatistics = new NuclearUI.ListView(Game.MainScreen)
				{
					AnchoredRect = NuclearUI.AnchoredRect.CreateTopLeftAnchored(0, 0, Game.MainScreen.Width - 50, 380)
				};
			DetailedStatistics.Columns.AddRange(new[]
				{
					new NuclearUI.ListViewColumn(DetailedStatistics, "Statistic", 250, NuclearUI.Anchor.Center)
				                                    .Perform(column => column.Label.Font = Game.UIStyle.LargeFont),
					new NuclearUI.ListViewColumn(DetailedStatistics, "Total Value", 150, NuclearUI.Anchor.Center)
				                                    .Perform(column => column.Label.Font = Game.UIStyle.LargeFont),
					new NuclearUI.ListViewColumn(DetailedStatistics, "Per Second", 150, NuclearUI.Anchor.Center)
				                                    .Perform(column => column.Label.Font = Game.UIStyle.LargeFont)
				});

			var playerNameLabel = new NuclearUI.Label(Game.MainScreen, playerName, Color.ForestGreen)
				{
					Font = Game.UIStyle.ExtraLargeFont
				};

			var backButton = new NuclearUI.Button(Game.MainScreen, "Back")
				{
					Font = Game.UIStyle.MediumFont,
					ClickHandler = button => Game.GameStateManager.DisplaySummary()
				};

			DisplayPanel = new NuclearUI.Panel(Game.MainScreen, Game.UIStyle.Panel, Game.UIStyle.PanelCornerSize)
				.Perform(
					mainPanel =>
					mainPanel.AddChild(
						new NuclearUI.BoxGroup(Game.MainScreen, NuclearUI.Orientation.Vertical, 0, NuclearUI.Anchor.Start)
							{
								AnchoredRect = NuclearUI.AnchoredRect.CreateFull(5)
							}
							.Perform(
								mainGroup =>
									{
										mainGroup.AddChild(playerNameLabel);
										mainGroup.AddChild(DetailedStatistics);
										mainGroup.AddChild(
											backButton.Perform(
												button =>
												button.AnchoredRect =
												NuclearUI.AnchoredRect.CreateTopLeftAnchored(0, 0, 110, Game.UIStyle.DefaultButtonHeight)));
									})));
		}

		/// <summary>
		/// Updates this instance.
		/// </summary>
		/// <param name="elapsedTime">The elapsed time.</param>
		public override void Update(float elapsedTime)
		{
			if (HasCombatLogChanged())
			{
				var playerStatistics = Game.CombatLogStatistics.Statistics.Single(pair => pair.Key == PlayerName);

				DetailedStatistics.Rows.Clear();
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Kills",
																																				new StatisticValue
																																				{
																																					TotalValue =
																																						playerStatistics.Value.TotalDamage.Count(
																																							CombatLogEntry.CombatFlags.Kill)
																																				}));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Overall Damage",
				                                                                playerStatistics.Value.TotalDamage[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Critical Damage",
				                                                                playerStatistics.Value.TotalDamage[CombatLogEntry.CombatFlags.Critical]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Critical Hits (%)",
				                                                                new StatisticValue
					                                                                {
						                                                                TotalValue =
							                                                                playerStatistics.Value.TotalDamage.Percentage(
								                                                                CombatLogEntry.CombatFlags.Critical)
					                                                                }));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Miss Hits (%)",
																																				new StatisticValue
																																				{
																																					TotalValue =
																																						playerStatistics.Value.TotalDamage.Percentage(
																																							CombatLogEntry.CombatFlags.Miss)
																																				}));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Peak Damage",
																																				playerStatistics.Value.PeakDamage[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Damage to Shields",
				                                                                playerStatistics.Value.DamageToShields[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Damage to Hull",
				                                                                playerStatistics.Value.DamageToHull[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Pet Damage",
																																				playerStatistics.Value.PetDamage[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Overall Healing",
				                                                                playerStatistics.Value.TotalHealing[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Shield Healing",
				                                                                playerStatistics.Value.ShieldHealing[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Hull Healing",
				                                                                playerStatistics.Value.HullHealing[CombatLogEntry.CombatFlags.Any]));
				DetailedStatistics.Rows.Add(CreateListViewRowForStatisticsEntry("Dummy", new StatisticValue()));
			}

			DetailedStatistics.Update(elapsedTime);
			DetailedStatistics.DoLayout(DetailedStatistics.LayoutRect);
		}

		/// <summary>
		/// Creates the list view row for statistics entry.
		/// </summary>
		/// <param name="entryName">Name of the entry.</param>
		/// <param name="value">The value.</param>
		/// <returns></returns>
		private NuclearUI.ListViewRow CreateListViewRowForStatisticsEntry(string entryName, StatisticValue value)
		{
			return new NuclearUI.ListViewRow(
				new NuclearUI.ListViewCell[]
					{
						new NuclearUI.ListViewTextCell(DetailedStatistics, entryName),
						new NuclearUI.ListViewTextCell(DetailedStatistics, GameHelpers.StatisticsValueToString(value.TotalValue)),
						new NuclearUI.ListViewTextCell(DetailedStatistics, GameHelpers.StatisticsValueToString(value.ValuePerSecond))
					},
				null);
		}

		/// <summary>
		/// Draws this instance.
		/// </summary>
		public override void Draw()
		{
			// Nothing todo here
		}

		/// <summary>
		/// Starts this instance.
		/// </summary>
		public override void Start()
		{
			Game.SetMainScreenContent(DisplayPanel);
			Game.CombatLogChanged += OnCombatLogChanged;

			base.Start();
		}

		/// <summary>
		/// Stops this instance.
		/// </summary>
		public override void Stop()
		{
			Game.CombatLogChanged -= OnCombatLogChanged;

			base.Stop();
		}

		#region CombatLog Changed Detection

		private bool combatLogChanged = true;
		private readonly object combatLogLockObject = new object();

		/// <summary>
		/// Called when [combat log changed].
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="args">The <see cref="EventArgs"/> instance containing the event data.</param>
		private void OnCombatLogChanged(object sender, EventArgs args)
		{
			lock (combatLogLockObject)
			{
				combatLogChanged = true;
			}
		}

		/// <summary>
		/// Determines whether the combat log has changed.
		/// </summary>
		/// <returns>
		///   <c>true</c> if the combat log has changed; otherwise, <c>false</c>.
		/// </returns>
		private bool HasCombatLogChanged()
		{
			lock (combatLogLockObject)
			{
				if (combatLogChanged)
				{
					combatLogChanged = false;
					return true;
				}
			}

			return false;
		}

		#endregion value.ToString("0");
	}
}
